using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;

namespace ProjectEuler.Core
{
    public class Problem17 : IProjectEulerProblem
    {
        protected IList<string> NumberWordsFrom1To(int n)
        {
            var list = new List<string>();
            for(int i=0;i<=n;i++)
            {
                list.Add(GetWord(i).Trim());
            }
            return list;
        }

        protected string GetWord(int i)
        {
            switch(i)
            {
                case 0:
                    return "";
                case 1:
                    return "one";
                case 2:
                    return "two";
                case 3:
                    return "three";
                case 4:
                    return "four";
                case 5:
                    return "five";
                case 6:
                    return "six";
                case 7:
                    return "seven";
                case 8:
                    return "eight";
                case 9:
                    return "nine";
                case 10:
                    return "ten";
                case 11:
                    return "eleven";
                case 12:
                    return "twelve";
                case 13:
                    return "thirteen";
                case 14:
                    return "fourteen";
                case 15:
                    return "fifteen";
                case 16:
                    return "sixteen";
                case 17:
                    return "seventeen";
                case 18:
                    return "eighteen";
                case 19:
                    return "nineteen";
                case 1000:
                    return "one thousand";
            }

            if(i >= 20 && i < 30)
            {
                return "twenty " + GetWord(i - 20);
            }
            if (i >= 30 && i < 40)
            {
                return "thirty " + GetWord(i - 30);
            }
            if (i >= 40 && i < 50)
            {
                return "forty " + GetWord(i - 40);
            }
            if (i >= 50 && i < 60)
            {
                return "fifty " + GetWord(i - 50);
            }
            if (i >= 60 && i < 70)
            {
                return "sixty " + GetWord(i - 60);
            }
            if (i >= 70 && i < 80)
            {
                return "seventy " + GetWord(i - 70);
            }
            if (i >= 80 && i < 90)
            {
                return "eighty " + GetWord(i - 80);
            }
            if (i >= 90 && i < 100)
            {
                return "ninety " + GetWord(i - 90);
            }

            int hundreds = i / 100;

            var part1 = GetWord(hundreds) + " hundred";
            var part2 = GetWord(i - (100*hundreds));

            return part1 + (part2 == "" ? "" : " and " + part2);
        }

        public int Number
        {
            get { return 17; }
        }

        public string Description
        {
            get
            {
                return
                    "If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words, how many letters would be used?";
            }
        }

        public string Answer
        {
            get { return NumberWordsFrom1To(1000).Aggregate((x, y) => x + y).Replace(" ", "").Length.ToString(); }
        }
    }

    [TestFixture]
    public class Problem17Tests : Problem17
    {
        [Test]
        public void Test_1()
        {
            Assert.AreEqual("one", GetWord(1));
        }

        [Test]
        public void Test_14()
        {
            Assert.AreEqual("fourteen", GetWord(14));
        }

        [Test]
        public void Test_21()
        {
            Assert.AreEqual("twenty one", GetWord(21));
        }

        [Test]
        public void Test_101()
        {
            Assert.AreEqual("one hundred and one", GetWord(101));
        }
    }
}
